home *** CD-ROM | disk | FTP | other *** search
- ;****************************************************************************
- ; file: files33.asm by: Steven M. Gibson, Irvine, CA created: 06/06/87
- ;****************************************************************************
- ;
- ; * * * PUBLIC DOMAIN COPYRIGHT RELEASE NOTICE * * *
- ;
- ; THIS PROGRAM, IN BOTH SOURCE CODE AND OBJECT FORM, HAS BEEN EXPLICITLY
- ; PLACED INTO THE PUBLIC DOMAIN BY ITS SOLE AUTHOR AND OWNER, STEVEN GIBSON,
- ; OF IRVINE, CA. IT MAY THEREFORE BE FREELY REPRODUCED, EXCHANGED, UPLOADED
- ; AND DOWNLOADED. HOWEVER THE AUTHOR REQUESTS THAT THIS NOTICE OF RELEASE
- ; AND ORIGIN OF AUTHORSHIP BE LEFT INTACT AND THAT THIS PROGRAM OR ITS DIRECT
- ; DERRIVATIVES, IF ANY, *NOT* BE SOLD FOR PROFIT. ALSO, PLEASE KEEP THE
- ; ENTIRE SET OF FILES TOGETHER AS ONE PACKAGE. ----> Thanks
- ;
- ;****************************************************************************
- ;
- ; About The Program: FILES.COM (source code file: files33.asm)
- ;
- ; "FILES.COM" is a small resident (TSR) program which overcomes a major
- ; glitch in the way IBM has implemented DOS 3.30. Specifically, it handles
- ; the requirements of explicitly ASKING DOS for additional handles and
- ; keeping a block of RAM available for DOS when this request is made.
- ; Any program can now have up to 256 files open when under 3.3 (counting
- ; the standard pre-opened default files) if the command "FILES" is issued
- ; first. This program also has the interesting ability to spontaneously
- ; remove itself ("Un-TSR") from memory after doing its job.
- ;
- ; If you wish to suppress the message FILES delivers when it is run, simply
- ; put anything after the command, (like: "files shhh") and it won't say a
- ; word as it goes resident. Otherwise it makes a short (non-commercial)
- ; statement of its intent as it terminates.
- ;
- ; NOTE: This program *ONLY* makes sense when under version 3.3 of DOS, and
- ; it will refuse to run under any earlier DOS versions. Use the
- ; other DOS 3.x version of FILES.COM (source file: files3x.asm)
- ;****************************************************************************
- ;
- ; About These SOURCE CODE FILES:
- ;
- ; This source code file, and the companion OPENER.ASM source code file, were
- ; written to be instructional, clear, and a bit tutorial in nature. As such
- ; they have been commented more heavily than normal self-communication
- ; would normally dictate. I hope you will find them interesting, useful,
- ; and not overly verbose. They are also examples of a general coding style
- ; I've found to endure quite well. Adopt it if you like it.
- ;
- ; NOTE: These files were created using the incredible file editor: BRIEF
- ;
- ;****************************************************************************
- ;
- ; To make a COM file from this ASM source code:
- ;
- ; masm files33, files33; <--- assemble the .asm to .obj
- ; link files33; <--- link the .obj to .exe
- ; exe2bin files33 files33.com <--- convert .exe to .com
- ; del files33.obj <--- delete the intermediate debris
- ; del files33.exe
- ;
- ;****************************************************************************
-
- ;----------------------------------------------------------------------------
- ; E Q U A T E S
- ;----------------------------------------------------------------------------
- CR equ 0Dh ; ASCII
- LF equ 0Ah
- COM_TERMINATE equ 20h ; .COM program termination
-
- DOS_FUNC equ 21h ; Interrupt to call DOS
- DOS_PRINTSTRING equ 09h ; Dos Sub-Function Defs
- DOS_SET_VECTOR equ 25h
- DOS_VERSION_NUMBER equ 30h ; " "
- DOS_STAY_RESIDENT equ 31h
- DOS_GET_VECTOR equ 35h
- DOS_CREATE equ 3Ch ; " "
- DOS_OPEN equ 3DH
- DOS_ALLOC equ 48H
- DOS_DEALLOC equ 49H ; " "
- DOS_SETBLOCK equ 4AH
- SET_HANDLE_COUNT equ 67h ; <----- The *NEW* function!
-
- NEW_HANDLE_COUNT equ 256 + 1 ; so we cam have 256 files
- NEW_MAX_HANDLES equ 256 ; assuming 256 handle params
- MINIMUM_VERSION equ 3 * 256 + 30 ; version "3"."30"
-
- ;----------------------------------------------------------------------------
- ; C O D E S E G M E N T
- ;----------------------------------------------------------------------------
- CODESEG SEGMENT BYTE PUBLIC
- ASSUME CS:CODESEG, DS:CODESEG
- ORG 02Ch ; pointer to this program's environ
- Environment LABEL WORD
-
- ORG 080h
- ParameterCount LABEL BYTE ; count of the command-line params
-
- ORG 100h ; .com programs execute from 0100h
- ComStart: jmp TransientCode ; jump over our resident portion
-
- ;****************************************************************************
- ; RESIDENT CODE PORTION BEGINS HERE
- ;****************************************************************************
-
- OldDosInt dd ? ; original int 21 vector pointer
- HoleSegment dw ? ; segment location of the "hole"
-
- ;----------------------------------------------------------------------------
-
- ;----------------------------------------------------------------------------
- ; NOTE TO THE READER: The following "resident portion" of the TSR will make
- ; *MUCH* more sense if you have FIRST read the "transient portion" below. I
- ; suggest that you jump ahead and read that first, then come back to here....
- ;----------------------------------------------------------------------------
-
- Int21Intercept:
- ;----------------------------------------------------------------------------
- ; The transient portion of this program pointed DOS' calling Interrupt 21
- ; here before terminating itself. Therefore we receive control every time
- ; anyone does an Int21h call to DOS. (Until we've fulfilled our mission)
- ;----------------------------------------------------------------------------
- cmp ah, DOS_OPEN ; was the call an open handle?
- je MakeRoom ; yep, see if we're alive
- cmp ah, DOS_CREATE ; was it a create handle?
- jne Int21Continue ; nope, so just pass it on
-
- MakeRoom: cmp cs:HoleSegment, 0 ; did we already do our thing?
- je Int21Continue ; yep, so don't do it again!
-
- push ax ; save the caller's calling
- push bx ; parameters on "his" stack
- push es
-
- ;----------------------------------------------------------------------------
- ; Free up the memory block, located at "HoleSegment", which was previously
- ; allocated by the transient portion of this program.
- ;----------------------------------------------------------------------------
- mov es, cs:HoleSegment ; get the segment number
- mov cs:HoleSegment, 0 ; zero it so we don't again
- mov ah, DOS_DEALLOC
- int DOS_FUNC ; and release that ram block
-
- ;----------------------------------------------------------------------------
- ; Now use DOS 3.3's new function: "Set Handle Count" to get DOS to use the
- ; RAM memory we've just now freed up for the purpose of allowing the handles
- ;----------------------------------------------------------------------------
- mov ah, SET_HANDLE_COUNT ; ask DOS for mucho handles
- mov bx, NEW_HANDLE_COUNT ; using the new 3.3 function
- int DOS_FUNC
-
- ;----------------------------------------------------------------------------
- ; Now we verrify that interrupt 21 is still pointing at us, and if so
- ; we're able to re-point it to where it was originally pointing, (thus
- ; un-vectoring ourselves) then release even ourselves from ram too!
- ;----------------------------------------------------------------------------
- mov ah, DOS_GET_VECTOR
- mov al, DOS_FUNC ; get int 21's address
- int DOS_FUNC
- cmp bx, OFFSET Int21Intercept
- jne RestoreStack ; it moved, so we must remain
- mov ax, es ;
- mov bx, cs ; can't compare segment regs,
- cmp ax, bx ; <sigh> so we do it this way
- jne RestoreStack
-
-
- ;----------------------------------------------------------------------------
- ; DOS' calling Interrupt 21 is still pointing at us, (as it should always be
- ; unless some later resident program or the currently executing program has
- ; changed it), so we're free to point it back to where it was pointing.
- ;----------------------------------------------------------------------------
- push dx ; we need ds and dx so we
- push ds ; stack them too for a moment
- mov dx, WORD PTR cs:OldDosInt
- mov ds, WORD PTR cs:OldDosInt+2
- mov ah, DOS_SET_VECTOR
- mov al, DOS_FUNC
- int DOS_FUNC
- pop ds ; and restore caller's ds:dx
- pop dx
-
- ;----------------------------------------------------------------------------
- ; Now, since we're no longer in the Interrupt 21 calling chain, we're free
- ; to leave ram too, so now we can release our own code segment as well!
- ; Since the transient portion already freed our environment allocation, and
- ; we just unhooked ourselves from Int21, this final release of our code seg
- ; will create a contiguous free region underneath the currently running
- ; application program which DOS will collect together and recover as soon
- ; as the program running now terminates. This means that we will have
- ; completely and spontaneously removed ourselves from RAM.
- ;----------------------------------------------------------------------------
- mov ax, cs ; get our own code segment
- mov es, ax
- mov ah, DOS_DEALLOC
- int DOS_FUNC ; and release our ram block
-
- ;----------------------------------------------------------------------------
- ; Now we restore the caller's original parameters (remember, we got control
- ; because he was doing a DOS call himself) and pass control on to DOS so
- ; that the caller's original job can be performed as if we were never here.
- ;----------------------------------------------------------------------------
- RestoreStack: pop es ; now restore our working
- pop bx ; registers
- pop ax
- Int21Continue: jmp cs:[OldDosInt] ; and "jump" to DOS so that
- ; and caller's return is
- ; left at the top of the stack
-
- ;****************************************************************************
- ; END OF THE RESIDENT CODE
- ;****************************************************************************
-
- ;----------------------------------------------------------------------------
-
-
- ;****************************************************************************
- ; BEGINNING OF THE TRANSIENT (NON-RESIDENT) CODE
- ;****************************************************************************
-
- ;----------------------------------------------------------------------------
- ; This program makes NO sense under any versions of DOS prior to 3.3, so we
- ; refuse to operate at all if we're using a prior DOS.
- ;----------------------------------------------------------------------------
- TransientCode: mov ah, DOS_VERSION_NUMBER ; first we need to make sure
- int DOS_FUNC ; this guy has DOS 3.3!
- xchg ah, al ; make the number linear
- cmp ax, MINIMUM_VERSION
- jae MakeUsResident ; yep, DOS ver 3.3 or later!
-
- mov dx, OFFSET WrongDosMsg ; nope, he's using a version
- mov ah, DOS_PRINTSTRING ; of DOS prior to 3.3
- int DOS_FUNC
- int COM_TERMINATE ; we're not "supposed" to quit
- ; this way anymore, but it's
- ; so easy!
- MakeUsResident:
- ;----------------------------------------------------------------------------
- ; When DOS loads a program it is allocated ALL of the remaining contiguous
- ; memory from its load-point to the end of ram, so we start by modifying
- ; this allocation so that it just encompasses our own program's code...
- ;----------------------------------------------------------------------------
- mov bx, OFFSET EndOfTransient + 15 ; get our ending offset
- mov cl, 4 ; and compute the number of
- shr bx, cl ; segments (the 15 rounds up)
- mov ah, DOS_SETBLOCK ; now shrink our memory block
- int DOS_FUNC
-
- ;----------------------------------------------------------------------------
- ; Every program also receives a set of strings in its Environment Block.
- ; Since we don't need this, it's polite to release it too. (Actually it's
- ; necessary if we, being a TSR, are ever to completely evacuate RAM.)
- ; (Dos manages memory allocation on a segment-by-segment, paragraph-by-
- ; paragraph basis. So we always refer to allocated blocks of memory by
- ; referencing that block's segment number. In the case of our Environment
- ; segment, our own PSP (program segment prefix) has a pointer to that seg.)
- ;----------------------------------------------------------------------------
- mov es, Environment ; get our environment's seg
- mov ah, DOS_DEALLOC
- int DOS_FUNC ; and release it too!
-
- ;----------------------------------------------------------------------------
- ; Now we grab up a block of memory large enough to allow DOS to open 256
- ; files. Our resident half will free this up when the time is right!
- ;----------------------------------------------------------------------------
- mov bx, (NEW_MAX_HANDLES+15)/16 ; use paragraphs
- mov ah, DOS_ALLOC
- int DOS_FUNC
- mov HoleSegment, ax ; and save the block's segment
- ; for our resident half
-
- ;----------------------------------------------------------------------------
- ; Now, since our whole methodology involves having the resident portion
- ; FREE UP this newly allocated ram block, then ask DOS for a lot of handles
- ; WHEN the next-to-run program asks DOS to open or create a file for it, we
- ; need to intercept all subsequent DOS calls until we're done with our job.
- ; So we re-route Interrupt 21 through our resident half.
- ;----------------------------------------------------------------------------
- mov ah, DOS_GET_VECTOR ; get the current
- mov al, DOS_FUNC ; interrupt 21 value
- int DOS_FUNC
- mov WORD PTR OldDosInt , bx ; saving it in the
- mov WORD PTR OldDosInt+2, es ; resident portion
-
- mov dx, OFFSET Int21Intercept ; that done, we set
- mov ah, DOS_SET_VECTOR ; int 21 to point
- mov al, DOS_FUNC ; to our resident
- int DOS_FUNC ; module
-
- ;----------------------------------------------------------------------------
- ; Nearly done, and just to be quite clear, we say something appropriate to
- ; our operator before we terminate ... but *ONLY* if he didn't specifically
- ; ask as to remain silent. The byte at location 80h in our PSP contains
- ; the count of parameters on our invoking command line. If this is not
- ; zero, we're suppose to suppress all departing exclamation....
- ;----------------------------------------------------------------------------
- cmp ParameterCount, 0 ; is it zero?
- jne NowWeTSR ; nope, so be quiet!
-
- mov dx, OFFSET FilesMessage ; yep, so we get to
- mov ah, DOS_PRINTSTRING ; say goodbye now
- int DOS_FUNC
-
- ;----------------------------------------------------------------------------
- ; Finally we tell DOS that we're all through, asking it nicely to terminate
- ; us but leave the first half of us resident. That top half will be awakened
- ; every time DOS is called until it's done its job. "TransientCode" is the
- ; beginning of our second half, and the "+15" does the right thing with
- ; rounding as we convert into our paragraph size.
- ;----------------------------------------------------------------------------
- NowWeTSR: mov ah, DOS_STAY_RESIDENT ; compute the number
- mov dx, OFFSET TransientCode + 15 ; of paragraphs to
- mov cl, 4 ; keep resident
- shr dx, cl
- int DOS_FUNC ; this "call", being "TSR" never gets
- ; control returned by DOS
- ;----------------------------------------------------------------------------
- ; T E X T M E S S A G E S
- ;----------------------------------------------------------------------------
- WrongDosMsg db CR,LF, "This program only applies to DOS versions "
- db "3.3 and (presumably) later. Sorry!",CR,LF,"$"
- FilesMessage db CR,LF
- db "The next program to run may open up to "
- db 22h,"FILES=",22h," files." ; asc(")=22h
- db CR,LF,"$"
- ;----------------------------------------------------------------------------
- EndOfTransient = THIS BYTE ; the address of this label is used
- ; to compute our load-module size
- CODESEG ENDS
- END ComStart ; and that's all there is to it!
-